﻿
Public Module _token
    'a serial of helper functions for token
    Public Function [false](ByVal c As Char) As Boolean
        Return False
    End Function

    'should not use inc
    Public Function [false](ByVal s As String, ByVal index As Int64, ByRef inc As Int64) As Boolean
        inc = 1
        Return False
    End Function

    Public Function falses(ByVal s As String, ByVal index As Int64, ByRef inc As Int64) As Boolean
        Return [false](s, index, inc)
    End Function

    Public Function [true](ByVal c As Char) As Boolean
        Return True
    End Function

    Public Function [true](ByVal s As String, ByVal index As Int64, ByRef inc As Int64) As Boolean
        inc = 1
        Return True
    End Function

    Public Function trues(ByVal s As String, ByVal index As Int64, ByRef inc As Int64) As Boolean
        Return [true](s, index, inc)
    End Function

    'a token means a serial of charactors, which start from firstcheck, and following with othercheck,
    'each space char before firstcheck will be ignored
    Public Function token(ByVal input As String, ByRef index As Int64, ByRef output As String, _
                          ByVal firstcheck As stringcheck, ByVal othercheck As stringcheck, _
                          Optional ByVal originalFirstCharCheck As charcheck = Nothing, _
                          Optional ByVal originalOtherCharCheck As charcheck = Nothing, _
                          Optional ByRef expectname As String = Nothing) As Boolean
        Dim i As Int64
        For i = index To strlen(input) - 1
            Dim inc As Int64
            If firstcheck(input, i, inc) Then
                Dim first As Int64
                first = i
                i += inc
                While i < strlen(input) AndAlso othercheck(input, i, inc)
                    i += inc
                End While

                output = strmid(input, first, i - first)
                index = i
                Return True
            ElseIf Not isspace(input(i)) Then
                Exit For
            End If
        Next

        If originalFirstCharCheck Is Nothing Then
            expectname = invokeMethodName(firstcheck)
        Else
            expectname = invokeMethodName(originalFirstCharCheck)
        End If
#If RETIRED Then
        If isdebugmode() Then
            expectname = expectname + " @ " + callstack(True)
        End If
#End If
        Return False
    End Function

    Private Class charcheckToStringcheck
        Private cc As charcheck = Nothing

        Public Sub New(ByVal cc As charcheck)
            Me.cc = cc
        End Sub

        Public Function stringcheck(ByVal s As String, ByVal index As Int64, ByRef inc As Int64) As Boolean
            If cc(s(index)) Then
                inc = 1
                Return True
            Else
                Return False
            End If
        End Function
    End Class

    Public Function token(ByVal input As String, ByRef index As Int64, ByRef output As String, _
                          ByVal firstcheck As charcheck, ByVal othercheck As charcheck, _
                          Optional ByRef expectname As String = Nothing) As Boolean
        Dim fcc As charcheckToStringcheck = Nothing
        Dim occ As charcheckToStringcheck = Nothing
        fcc = New charcheckToStringcheck(firstcheck)
        occ = New charcheckToStringcheck(othercheck)

        Return token(input, index, output, _
                     AddressOf fcc.stringcheck, AddressOf occ.stringcheck, _
                     firstcheck, othercheck, expectname)
    End Function
End Module
